/*
 * Copyright (c) 2008-2011, Petr Panteleyev
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without modification,
 * are permitted provided that the following conditions are met:
 *
 *    1. Redistributions of source code must retain the above copyright notice,
 *       this list of conditions and the following disclaimer.
 *    2. Redistributions in binary form must reproduce the above copyright notice,
 *       this list of conditions and the following disclaimer in the documentation
 *       and/or other materials provided with the distribution.
 *    3. The name of the author may not be used to endorse or promote products
 *       derived from this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
 * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
 * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR
 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
 * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
 * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 */

package org.panteleyev.blogclient;

import java.awt.Component;
import java.awt.event.KeyEvent;
import java.util.ArrayList;

import javax.swing.AbstractAction;
import javax.swing.Action;
import javax.swing.JFrame;
import javax.swing.JMenu;
import javax.swing.JMenuItem;
import javax.swing.JToolBar;
import javax.swing.KeyStroke;
import javax.swing.event.MenuListener;

import org.panteleyev.blogclient.options.OptionsDialog;
import org.panteleyev.swing.BaseFrame;
import org.panteleyev.swing.OSUtil;
import org.panteleyev.swing.SwingFactory;
import org.panteleyev.swing.WindowManager;
import org.panteleyev.swing.events.UpdateFrameEvent;
import org.panteleyev.utilities.ApplicationListener;
import org.panteleyev.utilities.Updatable;

/**
 *
 * @param <T>
 * @author Petr Panteleyev
 */
public class BloggerFrame<T extends UserProfile<?>> extends BaseFrame {
    private void constructor() {
        createActions();

        if (OSUtil.isMacOSX()) {
            OSUtil.setMacListener(new ApplicationListener() {
                @Override
                public void handleAbout() {
                    onAbout();
                }

                @Override
                public void handleQuit() {
                    exit();
                }

                @Override
                public void handlePreferences() {
                    onToolsOptions();
                }
            });
        }
    }

    public BloggerFrame() {
        constructor();
    }

    public BloggerFrame(T profile) {
        this.profile = profile;
        constructor();
    }

    public T getProfile() {
        return profile;
    }

    public void setProfile(T profile) {
        this.profile = profile;
    }

    @Override
    protected void beforeClosing() {
        super.beforeClosing();
        Options.saveBounds(this);
    }

    @Override
    public void setTitle(String title) {
        StringBuilder b = new StringBuilder();
        if (getProfile() != null) {
            b.append(getProfile().getName());
            if (!getProfile().isOnline()) {
                b.append(" [Offline]");
            }
            b.append(" - ");
        }
        b.append(title);
        super.setTitle(b.toString());
    }

    private void createActions() {
        int keyMask = BloggingKit.getKeyMask();

        connectAction = new AbstractAction(L10N.MAIN_FRAME_CONNECT_ACTION.s(), Icon.EMPTY.i()) {
            @Override
            public void actionPerformed(java.awt.event.ActionEvent evt) {
                onConnect();
            }
        };


        aboutAction = new AbstractAction(L10N.MAIN_FRAME_ABOUT_ACTION.s(), Icon.ABOUT.i()) {
            @Override
            public void actionPerformed(java.awt.event.ActionEvent evt) {
                onAbout();
            }
        };

        licenseAction = new AbstractAction(L10N.MAIN_FRAME_LICENSE_ACTION.s(), Icon.LICENSE.i()) {
            @Override
            public void actionPerformed(java.awt.event.ActionEvent evt) {
                new LicenseDialog(BloggerFrame.this).showDialog();
            }
        };

        homePageAction = new AbstractAction(L10N.MAIN_FRAME_HOMEPAGE_ACTION.s(), Icon.EARTH.i()) {
            @Override
            public void actionPerformed(java.awt.event.ActionEvent evt) {
                OSUtil.runBrowser(AboutDialog.HOMEPAGE);
            }
        };

        templatesAction = new AbstractAction(L10N.MAIN_FRAME_TEMPLATES_ACTION.s(), Icon.EMPTY.i()) {
            @Override
            public void actionPerformed(java.awt.event.ActionEvent evt) {
                onToolsTemplates();
            }
        };

        optionsAction = new AbstractAction(L10N.MAIN_FRAME_OPTIONS_ACTION.s(), Icon.OPTIONS.i()) {
            @Override
            public void actionPerformed(java.awt.event.ActionEvent evt) {
                onToolsOptions();
            }
        };

        typografAction = new AbstractAction(L10N.TYPOGRAF_MAIN_FRAME_ACTION.s(), Icon.EMPTY.i()) {
            @Override
            public void actionPerformed(java.awt.event.ActionEvent evt) {
                onTypograf();
            }
        };

        profileListAction = new AbstractAction(L10N.UPLF_TITLE.s(), Icon.EMPTY.i()) {
            @Override
            public void actionPerformed(java.awt.event.ActionEvent evt) {
                onUserProfiles();
            }
        };

        windowCloseAction = new AbstractAction(L10N.MAIN_FRAME_WINDOW_CLOSE_ACTION.s(), Icon.EMPTY.i()) {
            @Override
            public void actionPerformed(java.awt.event.ActionEvent evt) {
                closeFrame();
            }
        };
        windowCloseAction.putValue(Action.ACCELERATOR_KEY, KeyStroke.getKeyStroke(KeyEvent.VK_W, keyMask));

        if (this instanceof Updatable) {
            windowRefreshAction = new AbstractAction(L10N.MAIN_FRAME_WINDOW_REFRESH_ACTION.s(), Icon.RELOAD.i()) {
                @Override
                public void actionPerformed(java.awt.event.ActionEvent evt) {
                    receive(new UpdateFrameEvent(BloggerFrame.this));
                }
            };
            windowRefreshAction.putValue(Action.ACCELERATOR_KEY, KeyStroke.getKeyStroke(KeyEvent.VK_F5, 0));
            windowRefreshAction.putValue(Action.SHORT_DESCRIPTION, L10N.MAIN_FRAME_WINDOW_REFRESH_ACTION.s());
            windowRefreshAction.putValue(Action.LARGE_ICON_KEY, Icon.RELOAD.I());
        }
    }

    protected JMenu createToolsMenu() {
        return createMenu(L10N.MAIN_FRAME_MENU_TOOLS.s(), null,
            profileListAction,
            null,
            templatesAction,
            typografAction,
            (OSUtil.isMacOSX())? VOID : null,
            (OSUtil.isMacOSX())? VOID : optionsAction
        );
    }

    protected JMenu createWindowMenu() {
        windowMenu = createMenu(L10N.MAIN_FRAME_MENU_WINDOW.s(), null,
            (this instanceof Updatable)? windowRefreshAction : VOID,
            windowCloseAction,
            null
        );
        separatorPosition = windowMenu.getItemCount() - 1;

        windowMenu.addMenuListener(new MenuListener() {
            @Override
            public void menuSelected(javax.swing.event.MenuEvent evt) {
                onWindowMenuSelected();
            }
            @Override
            public void menuDeselected(javax.swing.event.MenuEvent evt) {
            }
            @Override
            public void menuCanceled(javax.swing.event.MenuEvent evt) {
            }
        });

        return windowMenu;
    }

    protected JMenu createHelpMenu() {
        return createMenu(L10N.MAIN_FRAME_MENU_HELP.s(), null,
            (OSUtil.isMacOSX())? VOID : aboutAction,
            (OSUtil.isMacOSX())? VOID : null,
            licenseAction,
            homePageAction
        );
    }

    protected void onAbout() {
        new AboutDialog(this).showDialog();
    }

    protected void onToolsOptions() {
        OptionsDialog d = new OptionsDialog(this);

        if (d.showDialog()) {
            UserProfileManager.saveProfiles();
        }
    }

    @Override
    public void exit() {
        Options.saveBounds(this);
        Options.storeSettings();
        System.exit(0);
    }

    public AbstractAction getAboutAction() {
        return aboutAction;
    }

    public void handleException(Throwable ex) {
        MainClass.handleException(this, ex);
    }

    public void onConnect() {
        if (UserProfileManager.getProfileCount() == 0) {
            return;
        }

        LoginDialog loginDialog = new LoginDialog(this);
        loginDialog.showDialog();

        if (loginDialog.isLoggedIn()) {
            UserProfile<?> prof = loginDialog.getProfile();
            prof.postLoginUIActions();
            prof.openStartupWindow();
        } else {
            if (WindowManager.getVisibleFramesCount() == 0) {
                System.exit(0);
            }
        }
    }

    protected JMenu createFileMenu() {
        return createMenu(L10N.MAIN_FRAME_MENU_FILE.s(), null,
            getConnectAction(),
            (OSUtil.isMacOSX())? BaseFrame.VOID : null,
            (OSUtil.isMacOSX())? BaseFrame.VOID : new ExitAction()
        );
    }

    protected JMenu createProfileMenu() {
        if (getProfile() == null) {
            throw new IllegalStateException();
        }

        return createMenu(
            getProfile().getProfileMenuName(), null,
            getProfile().getProfileActions().toArray()
        );
    }

    protected JToolBar createProfileToolBar(boolean floatable, boolean rollover) {
        return SwingFactory.createToolBar(floatable, rollover, getProfile().getProfileToolBarActions());
    }

    private void onTypograf() {
        JFrame frame = WindowManager.find(TypografFrame.class);

        if (frame == null) {
            frame = new TypografFrame();
        }

        frame.setVisible(true);
    }

    private void onUserProfiles() {
        JFrame frame = WindowManager.find(UserProfileListFrame.class);

        if (frame == null) {
            frame = new UserProfileListFrame();
        }

        frame.setVisible(true);
    }

    private void onToolsTemplates() {
        JFrame frame = WindowManager.find(TemplateListFrame.class);
        if (frame == null) {
            frame = new TemplateListFrame();
        }

        frame.setVisible(true);
    }

    private void onWindowMenuSelected() {
        // remove all menus after windowListSeparator
        int count = windowMenu.getItemCount();
        for (int index = count - 1; index > separatorPosition; index--) {
            windowMenu.remove(index);
        }

        Component comp = windowMenu.getMenuComponent(separatorPosition);
        ArrayList<BaseFrame> frs = WindowManager.getFrames();
        if (frs.isEmpty()) {
            comp.setVisible(false);
        } else {
            comp.setVisible(true);
            for (BaseFrame f : frs) {
                JMenuItem item = f.getMenuItem();
                windowMenu.add(item);
                item.setSelected(f == this);
            }
        }
    }

    protected AbstractAction getConnectAction() {
        return connectAction;
    }

    public AbstractAction getUpdateAction() {
        return windowRefreshAction;
    }

    /* Actions */
    private AbstractAction connectAction;
    private AbstractAction aboutAction;
    private AbstractAction licenseAction;
    private AbstractAction homePageAction;
    private AbstractAction templatesAction;
    private AbstractAction optionsAction;
    private AbstractAction typografAction;
    private AbstractAction windowCloseAction;
    private AbstractAction windowRefreshAction;
    private AbstractAction profileListAction;

    /* */
    private T profile;

    /* Window menu */
    private JMenu windowMenu;
    private int separatorPosition;
}
